/**
 * 点
 */
class point {
    constructor(x,y) {
		this.x = x;
		this.y = y;
	}
	
	/// 得到X
	x() {
		return this.x;
	}
	
	/// 得到Y
	y() {
		return this.y;
	}
	
	/// 设置X
	setX(x){
		this.x = x;
	}
	
	/// 设置Y
	setY(y){
		this.y = y;
	}
	
	/// 设置X,Y
	setXY(x,y){
		this.x = x;
		this.y = y;
	}
	
	/// 根据角度和半径得到另一个点
	getAngle(angle,radius){
		var radian = angle * Math.PI / 180;
		
		var b = this.y+Math.sin(radian) * radius;
		var a = this.x+Math.cos(radian) * radius;	
		
		return new point(a,b);	
	}

	/**
	 * 绕中心点旋转
	 * @param {*} ptRotationCenter  要旋转的中心点
	 * @param {*} angle 旋转的角度
	 * @returns 
	 */
	rotatePoint(ptRotationCenter,angle){
		var a = ptRotationCenter.x;
		var b = ptRotationCenter.y;
		var x0 = this.x;
		var y0 = this.y;
		var rx = a + (x0-a) * Math.cos(angle * Math.PI / 180) - (y0-b) * Math.sin(angle * Math.PI / 180);
		var ry = b + (x0-a) * Math.sin(angle * Math.PI / 180) + (y0-b) * Math.cos(angle * Math.PI / 180);

		return new point(rx,ry);
	}		
}

/**
 * 线
 */
class line {
	constructor(startpos,endpos) {
		this.startpos = startpos;
		this.endpos = endpos;
		this.boundingboxheight=10;
		this.polygons = [];
	}
	
	/// 得到开始结点
	startpos(){
		return this.startpos;
	}
	
	/// 得到结束结点
	endpos(){
		return this.endpos;
	}
	
	/// 设置包围盒高度
	setBoundingboxHeight(height){
		this.boundingboxheight=height;
	}
	
	/// 得到包围盒高度
	getBoundingboxHeight(){
		return this.boundingboxheight;
	}
	
	/**
	 * 得到线的角度
	 *
	 * @param reverse 如果设置成true,表示得到线的反向角度
	 */
	getAngle(reverse=false){
	    let angle = Math.atan2(this.startpos.y - this.endpos.y, this.startpos.x - this.endpos.x) * 180 / (Math.PI);
		
		if(reverse)
			angle = Math.atan2(this.endpos.y - this.startpos.y, this.endpos.x - this.startpos.x) * 180 / (Math.PI);
	  
	    return angle <= -90 ? (360 + angle) : angle;
	}
	
	/**
	 */
	getAngle2() {
	    let angle = Math.atan2(this.startpos.y - this.endpos.y, this.startpos.x - this.endpos.x) * 180 / (Math.PI);
	  
	    if(angle<0)
			angle = -angle;
		
	    return (180-angle)+180;		
	}
	
	/**
	 * 得到线的距离
	 */
	getDistance(){
		var dx = Math.abs(this.startpos.x - this.endpos.x);
		var dy = Math.abs(this.startpos.y - this.endpos.y);
		
		return Math.sqrt(Math.pow(dx,2)+Math.pow(dy,2));
	}
	
	/**
	 * 设置线的长度
	 *
	 * @param length 要设置的线的长度
	 * @param revers 是否反向设置线的长度
	 */
	setLength(length,reverse=false){
		var radian = (this.getAngle(reverse)+180) * Math.PI / 180;
	
		if(reverse == false){
			var b = this.startpos.y+Math.sin(radian) * length;
			var a = this.startpos.x+Math.cos(radian) * length;
		
			this.endpos.setXY(a,b);
			
			return this.endpos;
		}
		else{
			var b = this.endpos.y+Math.sin(radian) * length;
			var a = this.endpos.x+Math.cos(radian) * length;
			
			this.startpos.setXY(a,b);
			
			return this.startpos;
		}
	}
	
	/**
	 * 得到线上任一长度上的点
	 *
	 * @param length 要设置的线的长度
	 * @param revers 是否反向设置线的长度
	 */
	getLengthPoint(length,reverse=false){
		var radian = (this.getAngle(reverse)+180) * Math.PI / 180;
	
		if(reverse == false){
			var b = this.startpos.y+Math.sin(radian) * length;
			var a = this.startpos.x+Math.cos(radian) * length;
			
			return new point(a,b);
		}
		else{
			var b = this.endpos.y+Math.sin(radian) * length;
			var a = this.endpos.x+Math.cos(radian) * length;
			
			return new point(a,b);
		}
	}
	
	/**
	 * 得到线上任一点的法线
	 *
	 * @param position 要得到法线的点
	 * @param length 要设置的法线的长度
	 * @param revers 是否反向设置法线
	 */
	normalVector(position,reverse=false,length=-1){
		var dpoint = null;
						   
		if(!reverse){
			dpoint = new point(position.x+(this.endpos.y-this.startpos.y),
						   position.y-(this.endpos.x-this.startpos.x));
		}
		else{
			dpoint = new point(position.x+(this.startpos.y-this.endpos.y),
						   position.y-(this.startpos.x-this.endpos.x));
		}
		
		var tmpline = new line(position,dpoint);
		if(length == -1)
			return tmpline;
		
		tmpline.setLength(length);
		
		return tmpline;
	}
	
	/**
	 * 得到包围盒
	 */
	boundingBox(){	
		var tempLine = this.normalVector(this.getLengthPoint(0),false,this.boundingboxheight);
		this.polygons[0] = tempLine.endpos; 
		tempLine = this.normalVector(this.getLengthPoint(0),true,this.boundingboxheight);
		this.polygons[1] = tempLine.endpos;
		tempLine = this.normalVector(this.getLengthPoint(this.getDistance()),false,this.boundingboxheight);
		this.polygons[3] = tempLine.endpos; 
		tempLine = this.normalVector(this.getLengthPoint(this.getDistance()),true,this.boundingboxheight);
		this.polygons[2] = tempLine.endpos;
		
		return new polygon(this.polygons);		
	}
}

/**
 * 矩形
 */
class rect {
    constructor(x,y,w,h) {
		this.x = x;
		this.y = y;
		this.w = w;
		this.h = h;
	}
	
	/// 设置X,Y
	setXY(x,y) {
		this.x = x;
		this.y = y;
	}
	
	/// 设置矩形高宽
	setWidthAndHeight(w,h) {
		this.w = w;
		this.h = h;
	}
	
	/// 得到X
	getX() {
		return this.x;
	}
	
	/// 得到Y
	getY() {
		return this.y;
	}

	/// 得到结束X
	getX1() {
		return this.x+this.w;
	}

	/// 得到结束Y
	getY1() {
		return this.y+this.h;
	}

	/// 得到开始点
	getXY() {
		return new point(this.x,this.y);	
	}
	
	/// 得到矩形宽度
	getWidth() {
		return this.w;
	}
	
	/// 得到矩形高度
	getHeight() {
		return this.h;
	}
	
	/// 转Json数据
	toJson() {
		return "{x:"+this.getX()+",y:"+this.getY()+",x1="+this.getX1()+",y1="+this.getY1()+"}";
	}
	
	/// 得到矩形中心点
	getCenter() {
		return new point(this.x + this.w / 2,this.y + this.h / 2);
	}
	
    /// 检测矩形是否为空
	isEmpty() {
		if((this.x <= 0 && this.y <= 0) &&
		   (this.w <= 0 && this.h <= 0))
		   return true;
		   
		return false;
	}
	
	/// 检测一个点是否在矩形中
	PtInRect(x,y) {
		if((x >= this.x && x < (this.x+this.w)) &&
		   (y >= this.y && y < (this.y+this.h)))
		   return true;
		   
		return false;
	}
}

/**
 * 多边形
 */
class polygon {
	constructor(polygonarr){
		this.polygonpoints = [];
		for(let i=0;i<polygonarr.length;i++){
			this.polygonpoints[i] = new point(polygonarr[i].x,polygonarr[i].y);
		}
		this.totalpolygonarr = [];
		this.maxpoint = new point(polygonarr[0].x,polygonarr[0].y);
		this.boundingBoxrect = new rect(polygonarr[0].x,polygonarr[0].y,0,0);
		var index = 0;
		var tempMaxPoint = new point(polygonarr[0].x,polygonarr[0].y);

		for(let i=0;i<polygonarr.length;i++){
			this.totalpolygonarr[index++] = polygonarr[i].x;
			this.totalpolygonarr[index++] = polygonarr[i].y;
			
			if(polygonarr[i].x < this.maxpoint.x) this.maxpoint.x = polygonarr[i].x;
			if(polygonarr[i].x > this.maxpoint.y) this.maxpoint.y = polygonarr[i].x;

			if(polygonarr[i].x < this.boundingBoxrect.x) this.boundingBoxrect.x = polygonarr[i].x;
			if(polygonarr[i].y < this.boundingBoxrect.y) this.boundingBoxrect.y = polygonarr[i].y;

			if(polygonarr[i].x > tempMaxPoint.x) tempMaxPoint.x = polygonarr[i].x;
			if(polygonarr[i].y > tempMaxPoint.y) tempMaxPoint.y = polygonarr[i].y;
		}

		this.boundingBoxrect.w = tempMaxPoint.x - this.boundingBoxrect.x;
		this.boundingBoxrect.h = tempMaxPoint.y - this.boundingBoxrect.y;
	}

	/// 得到多边形的包围盒
	getboundingBoxrect() {
		return this.boundingBoxrect;
	}
	
	/**
	 * 得到多边形的点，返回x,y数组
	 */
	getPolygons() {
		return this.totalpolygonarr;
	}
	
	/**
	 * 得到多边形的点，以Point方式
	 */
	getPolygonPoints() {
		return this.polygonpoints;
	}	
	
	/**
	 * 得到多边形的边界
	 */
	getMaxPoint() {
		return this.maxpoint;
	}
	
	// 叫参数转换成json
	toJson() {		
		let tmpStr = "[";
		
		for(let i=0;i<this.polygonpoints.length;i++) {
			tmpStr += ("{x:"+this.polygonpoints[i].x+",y:"+this.polygonpoints[i].y+"},");
		}
		
		for(let i=0;i<this.totalpolygonarr.length;i+=2) {
			tmpStr += ("{x:"+this.totalpolygonarr[i]+",y:"+this.totalpolygonarr[i+1]+"},");
		}
		
		if(this.polygonpoints.length > 0) {
			tmpStr = tmpStr.substr(0,tmpStr.length-1) + "}";
		}
		else {
			tmpStr += "]";
		}
		
		return tmpStr;
	}
	
	/**
	 * 判断一个点是点击的多边形的前面还是后面
	 *
	 * @param point 要检测的点
	 */
	getClickdirection(point){
		var tmpline = new line(this.polygonpoints[0],this.polygonpoints[1])
		var tmppos = tmpline.getLengthPoint(tmpline.getDistance());
		tmpline = new line(tmppos,point);
		//console.log(tmpline.getDistance());
		if(tmpline.getDistance() < 20) return 1;          // 前面
		
		tmpline = new line(this.polygonpoints[2],this.polygonpoints[3])
		tmppos = tmpline.getLengthPoint(tmpline.getDistance());
		tmpline = new line(tmppos,point);
		//console.log(tmpline.getDistance());
		if(tmpline.getDistance() < 20) return 2;          // 后面		
		
		return 0;
	}

	/**
	 * 缩放结点
	 * @param length 长度
	 */
	scalePoints(length){
		let ptRotationCenter = this.getPolygonCentroid();//this.getboundingBoxrect().getCenter();

		for(let i=0;i<this.polygonpoints.length;i++){
			//let tmpLine = new line(ptRotationCenter,this.polygonpoints[i]);
			//this.polygonpoints[i] = tmpLine.getLengthPoint(tmpLine.getDistance()+length);
			this.polygonpoints[i].x = ptRotationCenter.x+(this.polygonpoints[i].x-ptRotationCenter.x)*length;
			this.polygonpoints[i].y = ptRotationCenter.y+(this.polygonpoints[i].y-ptRotationCenter.y)*length;
		}

		// 重置多边形
		this.resetPolygon();		
	}	

	/**
	 * 绕中心点旋转
	 * @param {*} angle 旋转的角度
	 * @param {*} rotationcenter 旋转的中心点
	 * @returns 
	 */
	 rotatePoint(angle,rotationcenter=null){
		if(this.polygonpoints.length <= 0)
			return false;

		let ptRotationCenter = this.getboundingBoxrect().getCenter();
		
		if(rotationcenter) {
			ptRotationCenter=rotationcenter;
		}
		
		for(let i=0;i<this.polygonpoints.length;i++){
			let a = ptRotationCenter.x;
			let b = ptRotationCenter.y;
			let x0 = this.polygonpoints[i].x;
			let y0 = this.polygonpoints[i].y;

			this.polygonpoints[i].x = a + (x0-a) * Math.cos(angle * Math.PI / 180) - (y0-b) * Math.sin(angle * Math.PI / 180);
			this.polygonpoints[i].y = b + (x0-a) * Math.sin(angle * Math.PI / 180) + (y0-b) * Math.cos(angle * Math.PI / 180);
		}	

		// 重置多边形
		this.resetPolygon();

		return true;
	}	
	
	/**
	 * 得到多边形的中心点
	 */
	getPolygonCentroid() {  
		let centroidX = 0;  
		let centroidY = 0;  
		let signedArea = 0;  
	  
		for (let i = 0; i < this.polygonpoints.length; i++) {  
			const j = (i + 1) % this.polygonpoints.length;  
			const x0 = this.polygonpoints[i].x;  
			const y0 = this.polygonpoints[i].y;  
			const x1 = this.polygonpoints[j].x;  
			const y1 = this.polygonpoints[j].y;  
	  
			const crossProduct = (x0 * y1) - (x1 * y0);  
			signedArea += crossProduct;  
	  
			centroidX += (x0 + x1) * crossProduct;  
			centroidY += (y0 + y1) * crossProduct;  
		}  
	  
		signedArea *= 0.5;  
		centroidX /= (6 * signedArea);  
		centroidY /= (6 * signedArea);  
	  
		return new point(centroidX,centroidY);
	}  
	
	// 重置多边形
	resetPolygon() {
		this.totalpolygonarr = [];
		this.maxpoint = new point(this.polygonpoints[0].x,this.polygonpoints[0].y);
		this.boundingBoxrect = new rect(this.polygonpoints[0].x,this.polygonpoints[0].y,0,0);
		var index = 0;
		var tempMaxPoint = new point(this.polygonpoints[0].x,this.polygonpoints[0].y);

		for(var i=0;i<this.polygonpoints.length;i++){
			this.totalpolygonarr[index++] = this.polygonpoints[i].x;
			this.totalpolygonarr[index++] = this.polygonpoints[i].y;
			
			if(this.polygonpoints[i].x < this.maxpoint.x) this.maxpoint.x = this.polygonpoints[i].x;
			if(this.polygonpoints[i].x > this.maxpoint.y) this.maxpoint.y = this.polygonpoints[i].x;

			if(this.polygonpoints[i].x < this.boundingBoxrect.x) this.boundingBoxrect.x = this.polygonpoints[i].x;
			if(this.polygonpoints[i].y < this.boundingBoxrect.y) this.boundingBoxrect.y = this.polygonpoints[i].y;

			if(this.polygonpoints[i].x > tempMaxPoint.x) tempMaxPoint.x = this.polygonpoints[i].x;
			if(this.polygonpoints[i].y > tempMaxPoint.y) tempMaxPoint.y = this.polygonpoints[i].y;
		}

		this.boundingBoxrect.w = tempMaxPoint.x - this.boundingBoxrect.x;
		this.boundingBoxrect.h = tempMaxPoint.y - this.boundingBoxrect.y;
	}
	
	/**
	 * 检测一个点是否在多边形内
	 *
	 * @param point 要检测的点
	 */
	ContainsPoint(point) {
	  if(this.totalpolygonarr.length <= 0)
		return false;
		
	  let n = this.totalpolygonarr.length >> 1;
	 
	  let ax, lup;
	  let ay = this.totalpolygonarr[2 * n - 3] - point.y;
	  let bx = this.totalpolygonarr[2 * n - 2] - point.x;
	  let by = this.totalpolygonarr[2 * n - 1] - point.y;
	 
	  if (bx === 0 && by === 0) return false; // point on edge
	 
	  // let lup = by > ay;
	  for (let ii = 0; ii < n; ii++) {
		ax = bx;
		ay = by;
		bx = this.totalpolygonarr[2 * ii] - point.x;
		by = this.totalpolygonarr[2 * ii + 1] - point.y;
		if (bx === 0 && by === 0) return false; // point on edge
		if (ay === by) continue;
		lup = by > ay;
	  }
	 
	  let depth = 0;
	  for (let i = 0; i < n; i++) {
		ax = bx;
		ay = by;
		bx = this.totalpolygonarr[2 * i] - point.x;
		by = this.totalpolygonarr[2 * i + 1] - point.y;
		if (ay < 0 && by < 0) continue; // both 'up' or both 'down'
		if (ay > 0 && by > 0) continue; // both 'up' or both 'down'
		if (ax < 0 && bx < 0) continue; // both points on the left
	 
		if (ay === by && Math.min(ax, bx) < 0) return true;
		if (ay === by) continue;
	 
		let lx = ax + ((bx - ax) * -ay) / (by - ay);
		if (lx === 0) return false; // point on edge
		if (lx > 0) depth++;
		if (ay === 0 && lup && by > ay) depth--; // hit vertex, both up
		if (ay === 0 && !lup && by < ay) depth--; // hit vertex, both down
		lup = by > ay;
	  }
	  return (depth & 1) === 1;
	}
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * 基础结点
 */
class scene_basenode {
	constructor(name,type){
		this.drawscene = null;                       // 绘制场景
		this.name = name;                            // 结点名称
		this.nodetype = type;                        // 结点类型
		this.childNodes = [];                        // 子结点
		this.parentNode = null;                      // 当前结点的父结点
		this.isVisible = true;                       // 是否显示
		this.isEnable = true;                        // 是否可用
		this.isShowboundingBox = false;              // 是否显示包围盒
		this.isscale=false;                          // 是否可以拉伸
		this.isdraggable=false;                      // 是否可以拖动
		this.rotateangle = 0.0;                      // 旋转的角度	
		this.scaleLength = 1.0;                      // 当前缩放的长度
		this.boundingBoxpolygon = null;              // 包围盒
		this.pointRateArray = [];                    // 当前结点坐标显示位置比例
		this.currentScenRect = null;                 // 当前场景范围
		this.originalpointArray = [];                // 当前结点原始坐标数组
		this.originalSceneRect = null;               // 原始场景范围  
		this.startDragPosition = null;               // 结点开始拖动位置
		this.showTip = false;                        // 是否提示		
		this.caption = "";                           // 提示字符串			
		this.mouseState = "";                        // 鼠标状态		
		this.oldshowTip = false;                     // 用于存储老的提示状态
		this.enableClip = true;                      // 是否启用裁剪，初始为启用
		this.baseImage = null;                       // 基础结点使用的基础图像
		this.baseImageSrcRect = null;                // 基础图像显示范围
		this.cornerRadius = 0.0;                     // 圆角半径

		this.strokeColor = '#ffffff';                // 边框颜色
		this.fillColor = '#ffffff';                  // 填充颜色
		this.isFill = false;                         // 是否填充
		this.lineWidth = 1;                          // 线条宽度

		this.boundingboxstrokeColor = '#ff00ff';     // 包围盒边框颜色
		this.boundingboxlineWidth = 1;               // 包围盒边框宽度
		this.isboundingboxFill=false;                // 包围盒是否要填充
		//this.boundingboxfillColor = '#ffffff';     // 包围盒填充颜色		

		this.mouseEvent = null;                      // 鼠标事件
		this.keyEvent = null;                        // 键盘事件
		this.imageLoadEvent = null;                  // 图片加载事件 
	}
	
	// 设置基础图像的显示范围
	setBaseImageSrcRect(rect){
		this.baseImageSrcRect = rect;
	}
	
	// 得到基础图像的显示范围
	getBaseImageSrcRect(){
		return this.baseImageSrcRect;
	}
	
	// 设置图片加载事件
	setImageLoadEvent(eevent){
		this.imageLoadEvent = eevent;
	}
	
	// 得到图片加载事件
	getImageLoadEvent(){
		return this.imageLoadEvent;
	}
	
	// 设置圆角半径
	setCornerRadius(radius){
		this.cornerRadius = radius;
	}
	
	/// 得到圆角半径
	getCornerRadius(){
		return this.cornerRadius;
	}
	
	// 设置是否启用裁剪
	setEnableClip(isenable){
		this.enableClip = isenable;
	}
	
	// 是否启用裁剪
	isEnableClip(){
		return this.enableClip;
	}
	
	// 设置是否提示
	setShowTip(isshow){
		this.showTip = isshow;
	}
	
	// 得到是否提示
	isShowTip(){
		return this.showTip;
	}	
	
	/// 设置当前结点是否支持拉伸
	setScaleable(isable){
		this.isscale = isable;
		
		for(let i=0;i<this.childNodes.length;i++){
			this.childNodes[i].setScaleable(isable);
		}			
	}
	
	/// 得到当前结点是否支持拉伸
	isScaleable(){
		return this.isscale;
	}
	
	/// 设置当前结点是否可以拖动
	setDraggable(isable){
		this.isdraggable = isable;
		
		for(let i=0;i<this.childNodes.length;i++){
			this.childNodes[i].setDraggable(isable);
		}			
	}
	
	/// 得到当前结点是否可以拖动
	isDraggable(){
		return this.isdraggable;
	}
	
	/// 导入图像
	loadImage(src) {
	  return new Promise((resolve, reject) => {
		var img = new Image();
		img.onload = function() {
		  resolve(img);
		};
		img.onerror = function() {
		  reject(new Error('图片加载失败'));
		};
		img.crossOrigin = 'anonymous'; // 设置crossorigin属性		
		img.src = src;
	  });
	}	
	
	/// 设置基础图像
	setBaseImage(src) {
	  if(src == "") return null;
	  
	  this.loadImage(src)
		  .then(img => {
			this.baseImage = img;
			//console.log(src+"加载成功.");
			this.baseImageSrcRect = new rect(0,0,this.baseImage.width,this.baseImage.height);
 			if(this.imageLoadEvent) this.imageLoadEvent(this,1);
		  })
		  .catch(error => {
			console.error(src+'图片加载失败.', error);
			if(this.imageLoadEvent) this.imageLoadEvent(this,0);
		  });
	  
	  return this.baseImage;
	}
	
	/// 得到基础图像
	getBaseImage(){
		return this.baseImage;
	}
	
	/// 重置当前结点的拖动位置
	resetStartDragPosition(){
		this.oldshowTip = this.showTip;
		this.showTip = false;
		this.startDragPosition = this.originalpointArray;
		
		for(let i=0;i<this.childNodes.length;i++){
			this.childNodes[i].resetStartDragPosition();
		}	
	}
	
	/// 改变渲染场景大小
	resizeScene(sceneRect){	

		let tmppointRateArray = [];

		for(let i=0;i<this.originalpointArray.length;i++){
			tmppointRateArray[i] = new point((this.originalpointArray[i].x-this.originalSceneRect.x) / this.originalSceneRect.w,
											(this.originalpointArray[i].y-this.originalSceneRect.y) / this.originalSceneRect.h);					
		}		
		
		this.originalSceneRect = sceneRect;	

		this.originalpointArray = [];
		for(let i=0;i<tmppointRateArray.length;i++){
			let drawrectx = this.originalSceneRect.x + this.originalSceneRect.w * tmppointRateArray[i].x;
			let drawrecty = this.originalSceneRect.y + this.originalSceneRect.h * tmppointRateArray[i].y;

			this.originalpointArray[i] = new point(drawrectx,drawrecty);
		}		
		
		this.rotateNode(this.rotateangle);		
		this.scaleNode(this.scaleLength);
	
		for(let i=0;i<this.childNodes.length;i++){
			this.childNodes[i].resizeScene(sceneRect);
		}		
	}
	
	/// 得到当前结点是否可以拖动
	isDraggable(){
		return this.isdraggable;
	}
	
	/// 设置绘制场景
	setDrawScene(scene) {
		this.drawscene = scene;
	}
	
	/// 得到绘制场景
	getDrawScene() {
		return this.drawscene;
	}
	
	/// 设置包围盒边框颜色
	setBoundingBoxStrokeColor(color) {
		this.boundingboxstrokeColor = color;		
	}
	
	/// 得到包围盒边框颜色
	getBoundingBoxStrokeColor() {
		return this.boundingboxstrokeColor;		
	}

	/// 添加一个子结点
	addChild(child) {
		// 设置父结点为自己
		child.parentNode = this;

		this.childNodes.push(child);
	}	

	/// 旋转结点
	rotateNode(angle,rotationcenter=null){
		this.rotateangle = angle;
			
		let tmpPolygon = new polygon(this.originalpointArray);
		tmpPolygon.rotatePoint(this.rotateangle,rotationcenter);
		tmpPolygon.scalePoints(this.scaleLength);
		let tmpPoints = tmpPolygon.getPolygonPoints();
		
		this.pointRateArray = [];
		for(let i=0;i<tmpPoints.length;i++){
			this.pointRateArray[i] = new point((tmpPoints[i].x-this.originalSceneRect.x) / this.originalSceneRect.w,
											(tmpPoints[i].y-this.originalSceneRect.y) / this.originalSceneRect.h);
		}
		
		// 旋转子结点
		for(let i=0;i<this.childNodes.length;i++){
			this.childNodes[i].rotateNode(angle,tmpPolygon.getboundingBoxrect().getCenter());
		}		
	}

	/// 缩放结点
	scaleNode(length){
		this.scaleLength = length;
			
		let tmpPolygon = new polygon(this.originalpointArray);
		tmpPolygon.rotatePoint(this.rotateangle);
		tmpPolygon.scalePoints(this.scaleLength);
		let tmpPoints = tmpPolygon.getPolygonPoints();
		this.pointRateArray = [];

		for(let i=0;i<tmpPoints.length;i++){
			this.pointRateArray[i] = new point((tmpPoints[i].x-this.originalSceneRect.x) / this.originalSceneRect.w,
											(tmpPoints[i].y-this.originalSceneRect.y) / this.originalSceneRect.h);					
		}
		
		// 缩放子结点
		for(let i=0;i<this.childNodes.length;i++){
			this.childNodes[i].scaleNode(length);
		}			
	}

	/// 移动结点
	moveNode(position){
		if(this.isdraggable == false)
		   return;
	   
		let tmpPosition = new point(position.x + this.startDragPosition[0].x,position.y + this.startDragPosition[0].y);	   
		
		let tmpPoints = [];
		tmpPoints[0] = tmpPosition;
		for(let i=1;i<this.startDragPosition.length;i++){
			let tmpline = new line(this.startDragPosition[0],this.startDragPosition[i]);
			tmpPoints[i] = tmpPosition.getAngle(tmpline.getAngle(true),tmpline.getDistance());
		}
		this.originalpointArray = tmpPoints;

		this.rotateNode(this.rotateangle);
		
		// 移动子结点
		for(let i=0;i<this.childNodes.length;i++){
			this.childNodes[i].moveNode(position);
		}			
	}

	/// 处理鼠标事件
	processMouseEvent(eventname,param1,param2) {
		if(this.mouseEvent == null)
			return false;
		
		this.mouseState = eventname;		

		return this.mouseEvent(eventname,param1,param2);
	}

	/// 处理键盘事件
	processKeyEvent(eventname,param1) {
		if(this.keyEvent == null)
			return false;

		return this.keyEvent(eventname,param1);
	}	

	/// 检测鼠标坐标是否在当前显示区域
	PtInDrawingRect(mouseX,mouseY) {
		if(this.boundingBoxpolygon == null)
			return false;

		return this.boundingBoxpolygon.ContainsPoint(new point(mouseX,mouseY));
	}	
	
	/// 检测鼠标坐标是否在当前结点的子结点显示区域
	PtInChildDrawingRect(mouseX,mouseY) {
		for(let i=0;i<this.childNodes.length;i++){
			if(this.childNodes[i].PtInDrawingRect(mouseX,mouseY)){
				return this.childNodes[i];
			}
		}

		return null;
	}	

	/// 更新结点
	updateNode(sceneRect){	
		this.currentScenRect = sceneRect;
	
		let tmpNewPostions = [];
		for(let i=0;i<this.pointRateArray.length;i++){
			let drawrectx = sceneRect.x + sceneRect.w * this.pointRateArray[i].x;
			let drawrecty = sceneRect.y + sceneRect.h * this.pointRateArray[i].y;

			tmpNewPostions[i] = new point(drawrectx,drawrecty);
			//console.log(i+":"+drawrectx+" "+drawrecty+" "+sceneRect.w+" "+sceneRect.h+" "+this.pointRateArray[i].x+" "+this.pointRateArray[i].y);
		}
		
		this.boundingBoxpolygon = new polygon(tmpNewPostions);
		
		// 更新子结点
		for(let i=0;i<this.childNodes.length;i++){
			this.childNodes[i].updateNode(sceneRect);
		}			
	}
	
	/// 绘制基础图像
	drawBaseImage(ctx){
		if(this.baseImage == null || !this.baseImage.complete || this.boundingBoxpolygon == null || this.baseImageSrcRect == null)
			return;
		
		//console.log(this.baseImageSrcRect.x+" "+this.baseImageSrcRect.y+" "+this.baseImageSrcRect.w+" "+this.baseImageSrcRect.h);
		
		let tmpPolygonPoints = this.boundingBoxpolygon.getPolygonPoints();
		let tmpboundingbox = this.boundingBoxpolygon.getboundingBoxrect();	
			
		if(this.nodetype == "多边形"){
			let tmppoints = [];
			tmppoints[0] = new point(tmpboundingbox.x,tmpboundingbox.y);	
			tmppoints[1] = new point(tmpboundingbox.x,tmpboundingbox.y+tmpboundingbox.h);	
			tmppoints[2] = new point(tmpboundingbox.x+tmpboundingbox.w,tmpboundingbox.y+tmpboundingbox.h);	
			tmppoints[3] = new point(tmpboundingbox.x+tmpboundingbox.w,tmpboundingbox.y);	
			//let tmppolygon = new polygon(tmppoints);
			//tmppolygon.rotatePoint(this.rotateangle);
			tmpPolygonPoints = tmppoints;	
		}	

		let tmpLine = new line(tmpPolygonPoints[0],tmpPolygonPoints[3]);
		let tmpBaseImageWidth = tmpLine.getDistance();
		let tmpBaseImageHeight = new line(tmpPolygonPoints[0],tmpPolygonPoints[1]).getDistance();		

		ctx.save();	
		ctx.beginPath();
		
		if(this.nodetype == "多边形"){
			let tmpCenterpos = tmpboundingbox.getCenter();
			ctx.translate(tmpCenterpos.x,tmpCenterpos.y);					  
			ctx.rotate(this.rotateangle*Math.PI/180);
			ctx.drawImage(this.baseImage,
						  this.baseImageSrcRect.x,this.baseImageSrcRect.y,
						  this.baseImageSrcRect.w,this.baseImageSrcRect.h,
						  -tmpboundingbox.w/2,-tmpboundingbox.h/2,
						  tmpboundingbox.w,tmpboundingbox.h);
			ctx.translate(-tmpCenterpos.x,-tmpCenterpos.y);
		}else{			
			ctx.translate(tmpPolygonPoints[0].x,tmpPolygonPoints[0].y);					  
			ctx.rotate(tmpLine.getAngle(true)*Math.PI/180);
			ctx.drawImage(this.baseImage,
						  this.baseImageSrcRect.x,this.baseImageSrcRect.y,
						  this.baseImageSrcRect.w,this.baseImageSrcRect.h,
						  0,0,
						  tmpBaseImageWidth,tmpBaseImageHeight);
			ctx.translate(-tmpPolygonPoints[0].x,-tmpPolygonPoints[0].y);
		}
		
		ctx.closePath();
		ctx.restore();					  
	}
	
	//绘制圆角多边形
	roundPolygonPath(p, r, ctx) {
	  //ctx.beginPath();
	  const startPoint = [
		(p[0][0] + p[p.length - 1][0]) / 2,
		(p[0][1] + p[p.length - 1][1]) / 2,
	  ];
	  ctx.moveTo(...startPoint);
	  for (let i = 0; i < p.length; i++) {
		if (i === p.length - 1) {
		  ctx.arcTo(...p[p.length - 1], ...p[0], r);
		} else {
		  ctx.arcTo(...p[i], ...p[i + 1], r);
		}
	  }
	  //ctx.closePath();
	}	

	/// 绘制包围盒
	drawBoundingBox(ctx){
		if(this.isShowboundingBox == false || this.boundingBoxpolygon == null)
			return;
		
		let tmpDecPoints = this.boundingBoxpolygon.getPolygonPoints();

		ctx.beginPath();
		//ctx.lineCap = 'round';
		ctx.strokeStyle=this.boundingboxstrokeColor;
		ctx.fillStyle=this.fillColor;
		ctx.lineWidth=this.boundingboxlineWidth;	
		//ctx.moveTo(tmpDecPoints[0].x+this.cornerRadius,tmpDecPoints[0].y);
		//ctx.lineTo(tmpDecPoints[tmpDecPoints.length-1].x-this.cornerRadius,tmpDecPoints[tmpDecPoints.length-1].y);

		//for(let i=tmpDecPoints.length-1;i>0;i--){
		//	ctx.arcTo(tmpDecPoints[i].x,tmpDecPoints[i].y,tmpDecPoints[i-1].x,tmpDecPoints[i-1].y,this.cornerRadius);
		//}

		//ctx.arcTo(tmpDecPoints[0].x,tmpDecPoints[0].y,tmpDecPoints[tmpDecPoints.length-1].x,tmpDecPoints[tmpDecPoints.length-1].y,this.cornerRadius);	
		let tmpPoints = [];
		for(let i=0;i<tmpDecPoints.length;i++){
			tmpPoints[i] = [];
			tmpPoints[i][0] = tmpDecPoints[i].x;
			tmpPoints[i][1] = tmpDecPoints[i].y;
		}
		
		this.roundPolygonPath(tmpPoints,this.cornerRadius,ctx);
		ctx.closePath();		
		ctx.stroke();
		if(this.isboundingboxFill) ctx.fill();	
		if(this.enableClip) ctx.clip();		

		// 绘制子结点包围盒
		for(let i=0;i<this.childNodes.length;i++){
			this.childNodes[i].drawBoundingBox(ctx);
		}	
	}

	/// 绘制结点
	drawNode(ctx){
		if(this.boundingBoxpolygon == null)
			return;

		ctx.save();
		
		/// 绘制包围盒
		this.drawBoundingBox(ctx);		
		
		/// 绘制基础图像
		this.drawBaseImage(ctx);

		// 绘制子结点
		for(let i=0;i<this.childNodes.length;i++){
			this.childNodes[i].drawNode(ctx);
		}	
		
		ctx.restore();		
	}
}

/**
 * 图片
 */
class scene_image extends scene_basenode {
	constructor(name,rect,imgpath) {
		super(name,"image");
	}
}

/**
 * 圆
 */
 class scene_circular extends scene_basenode {
	constructor(name,rect) {
		super(name,"circular");	
	}

	/// 绘制结点
	drawNode(ctx){
		if(this.boundingBoxpolygon == null)
			return;
		
		ctx.save();
		
		/// 绘制包围盒
		super.drawBoundingBox(ctx);		

		let tmpboundingbox = this.boundingBoxpolygon.getboundingBoxrect();
		let tmpPolygonPoints = this.boundingBoxpolygon.getPolygonPoints();
		let tmpcenterPos = tmpboundingbox.getCenter();			
		let startLine = new line(tmpPolygonPoints[0],tmpPolygonPoints[1]);
		let endLine = new line(tmpPolygonPoints[1],tmpPolygonPoints[2]);		
		let tmpstartPos =  startLine.getLengthPoint(startLine.getDistance()/2);
		let tmpendPos = endLine.getLengthPoint(endLine.getDistance()/2);
		let tmpRadiusW = new line(tmpcenterPos,tmpstartPos).getDistance();
		let tmpRadiusH = new line(tmpcenterPos,tmpendPos).getDistance();	

		ctx.strokeStyle=this.strokeColor;
		ctx.fillStyle=this.fillColor;
		ctx.lineWidth=this.lineWidth;		
		ctx.beginPath();
		ctx.ellipse(tmpcenterPos.x,tmpcenterPos.y,
					tmpRadiusW,tmpRadiusH,
					0,0,
					Math.PI*2);
		ctx.stroke();
		if(this.enableClip) ctx.clip();				
		if(this.isFill) ctx.fill();		
		ctx.closePath();	
		
		/// 绘制基础图像
		super.drawBaseImage(ctx);			

		ctx.restore();		
	}		
}

/**
 * 线段
 */
 class scene_line extends scene_basenode {
	constructor(name,startpos,endpos){
		super(name,"文本");

		this.lineNode = new line(startpos,endpos);		
	}

	/// 绘制结点
	drawNode(ctx){
		if(this.boundingBoxpolygon == null)
			return;
		
		ctx.save();
		
		/// 绘制包围盒
		super.drawBoundingBox(ctx);	

		/// 绘制基础图像
		super.drawBaseImage(ctx);			

		//let tmpboundingbox = this.boundingBoxpolygon.getboundingBoxrect();
		let tmpPolygonPoints = this.boundingBoxpolygon.getPolygonPoints();	
		let startLine = new line(tmpPolygonPoints[0],tmpPolygonPoints[1]);
		let endLine = new line(tmpPolygonPoints[2],tmpPolygonPoints[3]);
		let tmpstartPos =  startLine.getLengthPoint(startLine.getDistance()/2);
		let tmpendPos = endLine.getLengthPoint(endLine.getDistance()/2);

		ctx.beginPath();
		//ctx.lineCap = 'round';
		ctx.strokeStyle=this.strokeColor;
		ctx.lineWidth=this.lineWidth;	
		ctx.moveTo(tmpstartPos.x,tmpstartPos.y);
		ctx.lineTo(tmpendPos.x,tmpendPos.y);
		ctx.stroke();
		ctx.closePath();			
	
		ctx.restore();
	}	
}

/**
 * 文本
 */
 class scene_text extends scene_basenode {
	constructor(name,title,font='16px Calibri'){
		super(name,"文本");
		               
		this.font = font;                            // 使用的字体
		this.fontSize = 0;                           // 字体大小
		this.textAlign = 'left';                  // 字体水平对齐方式	
		this.textBaseline = 'middle';            // 字体垂直对齐方式

		this.title = title;                       // 要显示的文本    
	}

	// 设置垂直对齐方式
	settextBaseline(baseline) {
		this.textBaseline = baseline;
	}

	// 得到垂直对齐方式
	gettextBaseline() {
		return this.textBaseline;
	}

	// 设置水平对齐方式
	settextAlign(align) {
		this.textAlign = align;
	}

	// 得到水平对齐方式
	gettextAlign() {
		return this.textAlign;
	}

	// 得到字体大小
	getfontSize() {
		return this.fontSize;
	}

	// 设置要显示的文本
	setTitle(title) {
		this.title = title;
	}

	// 得到要显示的文本
	getTitle() {
		return this.title;
	}

	/// 绘制结点
	drawNode(ctx){
		if(this.boundingBoxpolygon == null)
			return;
		
		ctx.save();
		
		/// 绘制包围盒
		super.drawBoundingBox(ctx);				
		
		/// 绘制基础图像
		super.drawBaseImage(ctx);			
	
		let tmpboundingbox = this.boundingBoxpolygon.getboundingBoxrect();
		let tmpPolygonPoints = this.boundingBoxpolygon.getPolygonPoints();	
		let tmpLine1 = new line(tmpPolygonPoints[2],tmpPolygonPoints[1]);
		let tmpLine2 = new line(tmpPolygonPoints[0],tmpPolygonPoints[1]);
		let tmpboundingboxW = tmpLine1.getDistance();
		let tmpboundingboxH = tmpLine2.getDistance();
		let tmpcenterPos = tmpboundingbox.getCenter();
		
		if(this.rotateangle > 90 && this.rotateangle < 270) {
			tmpLine1 = new line(tmpPolygonPoints[1],tmpPolygonPoints[2]);
		}

		let tmpRelcoord = new point(0,0);
		this.fontSize = tmpboundingboxH/2;
		let tmpTitle = this.title;		

		if(this.textAlign == 'start' || this.textAlign == 'left'){
			tmpRelcoord.x = -tmpboundingboxW/2;
		}
		else if(this.textAlign == 'end' || this.textAlign == 'right'){
			tmpRelcoord.x = tmpboundingboxW/2;
		}	
		
		if(this.textBaseline == 'Bottom' || this.textBaseline == 'Alphabetic'){
			tmpRelcoord.y = tmpboundingboxH/2-4;
		}
		else if(this.textBaseline == 'Top' || this.textBaseline == 'Hanging'){
			tmpRelcoord.y = -tmpboundingboxH/2+this.fontSize+3;
		}			

		ctx.save();		
		ctx.beginPath();
		ctx.strokeStyle=this.strokeColor;
		ctx.fillStyle=this.fillColor;
		ctx.lineWidth=this.lineWidth;
		ctx.font = this.fontSize+'pt Calibri';
		ctx.textAlign = this.textAlign;
		ctx.textBaseline = this.textBaseline;					
		ctx.translate(tmpcenterPos.x,tmpcenterPos.y);
		ctx.rotate(tmpLine1.getAngle()*Math.PI/180);
		ctx.fillText(tmpTitle,tmpRelcoord.x,tmpRelcoord.y);
		ctx.translate(-tmpcenterPos.x,-tmpcenterPos.y);
		ctx.closePath();
		ctx.restore();	
	
		ctx.restore();
	}	
}

/**
 * 矩形
 */
class scene_rectangle extends scene_basenode {
	constructor(name,decrect,angle=0.0,caption=""){
		super(name,"矩形");
		               
		this.decrect = decrect;                      // 目标范围
		this.angle = angle;                          // 目标角度
		this.caption = caption;                      // 显示字符串	
		this.textctrl = null;                        // 文本控件
	}
	
	// 设置显示字符串
	setCaption(caption,isEllipsis=true){
		if(this.textctrl == null)
			return;
		
		this.caption = caption;  
		this.showTip = false;
		
		if(isEllipsis){
			// 保存canvas老的字体
			let tmpoldfont = this.drawscene.font;
			
			// 设置新的字体
			this.drawscene.font = this.textctrl.font;
			
			let textHeight = parseInt(this.drawscene.font.match(/\d+(px)?/)[0], 10); 		
			let textWidth = this.drawscene.measureText(caption).width;
			
			let rectWidth = this.originalpointArray[2].x - this.originalpointArray[0].x;
			let tmpCaption = "";
			let i=0;
			
			for(;i<caption.length;i++){
				tmpCaption += caption.at(i);
				if(this.drawscene.measureText(tmpCaption + "...").width  > rectWidth)
					break;
			}		
			
			// 还原为老的字体
			this.drawscene.font = tmpoldfont;
				
			this.showTip = true;		
			this.textctrl.setTitle(caption.substr(0,i-1)+"...");
		}
		else {
			this.textctrl.setTitle(caption);
		}
	}
	
	// 得到显示字符串
	getCaption(){
		return this.caption;
	}
	
	// 设置字符串显示颜色
	setTextColor(color){
		if(this.textctrl == null)
			return;
		
		this.textctrl.fillColor=color;
	}
	
	// 得到字符串显示颜色
	getTextColor(){
		if(this.textctrl == null)
			return "";
		
		return this.textctrl.fillColor;
	}
	
	// 设置字符串对齐方式
	setTextAlign(align){
		if(this.textctrl == null)
			return;
		
		this.textctrl.textAlign=align;
	}
	
	// 得到字符串对齐方式
	getTextAlign(){
		if(this.textctrl == null)
			return "";
		
		return this.textctrl.textAlign;
	}
	
	// 设置字体
	setFont(font){
		if(this.textctrl == null || font == "" || this.textctrl.font == font)
			return;
		
		this.textctrl.font = font;
		
		// 保存canvas老的字体
		let tmpoldfont = this.drawscene.font;
		// 设置新的字体
		this.drawscene.font = font;
		
		let textHeight = parseInt(this.drawscene.font.match(/\d+(px)?/)[0], 10); 		
		let textWidth = this.originalpointArray[2].x - this.originalpointArray[0].x;
		
		// 还原为老的字体
		this.drawscene.font = tmpoldfont;
		
		// 字符控件始终显示在中间
		let tmpRectHeight = this.originalpointArray[2].y - this.originalpointArray[0].y;		
		let tmpDecRectY = this.originalpointArray[0].y+tmpRectHeight/2-textHeight/2;

		let tmpPoints = [];
		tmpPoints[0] = new point(this.originalpointArray[0].x,tmpDecRectY);
		tmpPoints[1] = new point(this.originalpointArray[0].x,tmpDecRectY+textHeight);
		tmpPoints[2] = new point(this.originalpointArray[0].x+textWidth,tmpDecRectY+textHeight);
		tmpPoints[3] = new point(this.originalpointArray[0].x+textWidth,tmpDecRectY);
		this.textctrl.originalpointArray = tmpPoints;
		
		if(this.textctrl.rotateangle == 0.0){
			let tmpRates = [];
			for(let i=0;i<tmpPoints.length;i++){
				tmpRates[i] = new point(tmpPoints[i].x / this.originalSceneRect.w,
										tmpPoints[i].y / this.originalSceneRect.h);
			}
			this.textctrl.pointRateArray = tmpRates;
		}else{
			this.textctrl.rotateNode(this.textctrl.rotateangle);
		}
	}
	
	// 得到字体
	getFont(){
		if(this.textctrl == null)
			return "";
		
		return this.textctrl.font;
	}
	
	/// 处理鼠标事件
	processMouseEvent(eventname,param1,param2) {	
		return super.processMouseEvent(eventname,param1,param2);
	}	
	
	/// 绘制结点
	drawNode(ctx){
		if(this.boundingBoxpolygon == null)
			return;
		
		ctx.save();
		
		/// 绘制包围盒
		super.drawBoundingBox(ctx);	

		/// 绘制基础图像
		super.drawBaseImage(ctx);			
		
		/// 绘制结点
		super.drawNode(ctx);
		
		ctx.restore();
	}		
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * 场景管理
 */
 class scenesmanager extends scene_basenode {
	/**
	 * 
	 * @param {*} drawcanvas   要绑定的canvas
	 * @param {*} intervaltime  刷新时间，如果设置成0，不自动刷新
	 * @param {*} scale  是否支持场景缩放
	 * @param {*} draggable 是否支持场景拖动
	 */
	constructor(drawcanvas,intervaltime=0,scale=false,draggable=false,adaptivescreen=false){
		super("scenesmanager","scenemanager");

		this.tmpcanvas = document.getElementById(drawcanvas);
		this.drawscene = this.tmpcanvas.getContext("2d");
		//this.drawscene.translate(0.5, 0.5);
		this.canvasrect = this.tmpcanvas.getBoundingClientRect();
		this.originalSceneRect = new rect(0,0,this.canvasrect.width,this.canvasrect.height);
		this.scale = scale;
		this.draggable = draggable;
		this.adaptivescreen = adaptivescreen;

		let that = this;
		let isDragged = false;
		let tmpboundingbox = this.originalSceneRect;
		let currentMouseOverNode = null;                  // 当前鼠标所在结点，用于处理鼠标移开消息
		let currentdraggableNode = null;                  // 当前可以拖动的结点
		let tmpstartpos = null;
		let tmpendpos = null;	
		let tmpMouseX = 0;
		let tmpMouseY = 0;	

		let systemLogFunction = null;                     // 系统日志输出函数
		let systemResizeSceneFunction = null;             // 系统场景改变函数
		
		// 检测当前浏览器是否支持canvas
		if (this.drawscene == null) {
			alert('当前浏览器不支持canvas。');
			return;
		}
			
		// 自适应屏幕
		window.addEventListener('resize', function(){
			that.adaptiveScene();		
		}, false);  

		// 鼠标事件处理(滚轮事件)
		this.tmpcanvas.onmousewheel = function(e){
			let isConnectEvent = false;

			if(that.originalSceneRect.PtInRect(tmpMouseX,tmpMouseY)) {		
				// 处理场景中子结点事件
				var tmpNode = that.PtInChildDrawingRect(tmpMouseX,tmpMouseY);
				if(tmpNode){
					isConnectEvent = tmpNode.processMouseEvent("wheel",(e.wheelDelta > 0 || e.detail < 0 ? true : false),0);
				}	
			}			

			if(!isConnectEvent){
				// 处理场景事件
				isConnectEvent = that.processMouseEvent("wheel",(e.wheelDelta > 0 || e.detail < 0 ? true : false),0);
			}	

			// 是否支持场景缩放
			if(!isConnectEvent){
				if(scale){
					if(e.wheelDelta > 0 || e.detail < 0){
						that.wheelScene(1);
					}else {
						that.wheelScene(-1);    
					}
				}	
				else {
					if(that.currentMouseOverNode){
						if(e.wheelDelta > 0 || e.detail < 0){
							that.wheelNode(that.currentMouseOverNode,0.01);
						}else {
							that.wheelNode(that.currentMouseOverNode,-0.01);    
						}					
					}
				}
			}			
		}	
		// 鼠标事件处理(鼠标按下事件)		
		this.tmpcanvas.onmousedown = function(e){		
			const tmpClientRect = that.tmpcanvas.getBoundingClientRect();  
			tmpMouseX = e.clientX-tmpClientRect.left;
			tmpMouseY = e.clientY-tmpClientRect.top;
			
			let isConnectEvent = false;
					
			// 处理场景中子结点事件
			let tmpNode = that.PtInChildDrawingRect(tmpMouseX,tmpMouseY);
			if(tmpNode && this.currentdraggableNode == null){
				isConnectEvent = tmpNode.processMouseEvent("down",tmpMouseX,tmpMouseY);
			}	
			
			if(!isConnectEvent){
				// 先处理场景事件
				isConnectEvent = that.processMouseEvent("down",tmpMouseX,tmpMouseY);		
			}	

			// 检测结点是否可以拖动
			if(tmpNode && 
			   tmpNode.isdraggable){
				this.currentdraggableNode = tmpNode;
			}			

			if((that.draggable && !isConnectEvent) ||
			    this.currentdraggableNode){
				// 是否支持场景拖动	
				if(isDragged || !that.originalSceneRect.PtInRect(tmpMouseX,tmpMouseY))
					return;
				
				isDragged = true;
				if(this.currentdraggableNode){
					this.currentdraggableNode.resetStartDragPosition();
				}
				else{
					tmpboundingbox = that.originalSceneRect;
				}
				
				tmpstartpos = new point(e.clientX,e.clientY);	
			}
		}
		// 鼠标事件处理(鼠标移动事件)	
		this.tmpcanvas.onmousemove = function(e){
			const tmpClientRect = that.tmpcanvas.getBoundingClientRect();  
			tmpMouseX = e.clientX-tmpClientRect.left;
			tmpMouseY = e.clientY-tmpClientRect.top;
			
			//console.log(tmpMouseX+" "+tmpMouseY+"|"
			//			+e.clientX+" "+e.clientY);			
								
			let isConnectEvent = false;
			
			// 处理场景中子结点事件
			let tmpNode = that.PtInChildDrawingRect(tmpMouseX,tmpMouseY);
			if(tmpNode && this.currentdraggableNode == null){
				isConnectEvent = tmpNode.processMouseEvent("move",tmpMouseX,tmpMouseY);
			}

			// 如果鼠标移开某个结点，发送数据移开消息
			if(that.currentMouseOverNode != tmpNode){
				if(that.currentMouseOverNode){
					that.currentMouseOverNode.processMouseEvent("moveout",tmpMouseX,tmpMouseY);
				}

				that.currentMouseOverNode=tmpNode;
			}

			if(!isConnectEvent){
				// 先处理场景事件
				isConnectEvent = that.processMouseEvent("move",tmpMouseX,tmpMouseY);
			}	

			// 是否支持场景拖动
			if((that.draggable && !isConnectEvent) || 
			    this.currentdraggableNode){				
				if(isDragged && tmpstartpos){
					tmpendpos = new point(e.clientX-tmpstartpos.x,e.clientY-tmpstartpos.y);	
					
					if(this.currentdraggableNode){
						this.currentdraggableNode.moveNode(tmpendpos);
					}
					else{
						that.resizeScenePosition(tmpboundingbox.x+tmpendpos.x,tmpboundingbox.y+tmpendpos.y);
					}
				}
			}
		}	
		// 鼠标事件处理(鼠标抬起事件)		
		this.tmpcanvas.onmouseup = function(e){		
			const tmpClientRect = that.tmpcanvas.getBoundingClientRect(); 
			tmpMouseX = e.clientX-tmpClientRect.left;
			tmpMouseY = e.clientY-tmpClientRect.top;

			let isConnectEvent = false;

			// 处理场景中子结点事件
			let tmpNode = that.PtInChildDrawingRect(tmpMouseX,tmpMouseY);
			if(tmpNode && this.currentdraggableNode == null){
				isConnectEvent = tmpNode.processMouseEvent("up",tmpMouseX,tmpMouseY);
			}	
			
			if(!isConnectEvent){
				// 先处理场景事件
				isConnectEvent = that.processMouseEvent("up",tmpMouseX,tmpMouseY);	
			}	

			// 是否支持场景拖动
			if((that.draggable && !isConnectEvent) ||
			    this.currentdraggableNode){				
				if(isDragged && tmpstartpos){
					tmpendpos = new point(e.clientX-tmpstartpos.x,e.clientY-tmpstartpos.y);	
					
					if(this.currentdraggableNode){
						this.currentdraggableNode.moveNode(tmpendpos);
						
						// 恢复开始的提示状态
						this.currentdraggableNode.setShowTip(this.currentdraggableNode.oldshowTip);
					}
					else{
						that.resizeScenePosition(tmpboundingbox.x+tmpendpos.x,tmpboundingbox.y+tmpendpos.y);
					}
				}	
				
				isDragged = false;
				this.currentdraggableNode = null;
			}
		}

		// 键盘事件处理
		window.addEventListener('keyup', (e) => {
		
		});
		window.addEventListener('keydown', (e) => {
	
		});	

		// 是否自动刷新场景
		if(intervaltime > 0){
        	setInterval(function(){
				that.updateScene();
				that.adaptiveScene();          // 场景自适应
				that.drawScene();
			},intervaltime);
		}		
	}
	
	/// 设置系统日志输出函数
	setSystemLogFunction(func){
		this.systemLogFunction = func;
	}
	
	/// 得到系统日志输出函数
	getSystemLogFunction(){
		return this.systemLogFunction;
	}
	
	/// 设置系统场景改变函数
	setSystemResizeSceneFunction(func){
		this.systemResizeSceneFunction = func;
	}
	
	/// 得到系统场景改变函数
	getSystemResizeSceneFunction(){
		return this.systemResizeSceneFunction;
	}
	
	/**
	 * 添加一个图片
	 * @param name 图片的名称
	 * @param position 图片的显示位置
	 * @param imgpath, 图片的路径
	 * @param angle 图片的显示角度
	 */
	addImage(name,decrect,imgpath,func=null,angle=0.0) {	
		let tmpSceneImage = new scene_image(name,"图片");
		tmpSceneImage.originalSceneRect = this.originalSceneRect;
		tmpSceneImage.rotateangle = angle;
		//tmpSceneImage.originalpointArray = points;
		tmpSceneImage.isboundingboxFill = true;
		tmpSceneImage.isShowboundingBox = true;
		
		tmpSceneImage.setImageLoadEvent(func);
		tmpSceneImage.setBaseImage(imgpath);	
		
		let tmpPoints = [];
		tmpPoints[0] = new point(decrect.x,decrect.y);
		tmpPoints[1] = new point(decrect.x,decrect.y+decrect.h);
		tmpPoints[2] = new point(decrect.x+decrect.w,decrect.y+decrect.h);
		tmpPoints[3] = new point(decrect.x+decrect.w,decrect.y);
		tmpSceneImage.originalpointArray = tmpPoints;

		let tmpRates = [];
		for(let i=0;i<tmpPoints.length;i++){
			tmpRates[i] = new point(tmpPoints[i].x / this.originalSceneRect.w,
				tmpPoints[i].y / this.originalSceneRect.h);
		}
		tmpSceneImage.pointRateArray = tmpRates;

		if(tmpSceneImage.rotateangle != 0.0){
			tmpSceneImage.rotateNode(tmpSceneImage.rotateangle);
		}

		super.addChild(tmpSceneImage);

		return tmpSceneImage;		
	}

	/**
	 * 添加一个多边形
	 * @param name 多边形的名称
	 * @param points 多边形的点数组
	 * @param angle 多边形的显示的角度,初始是0
	 */
	addPolygon(name,points,angle=0.0) {
		let tmpPolygon = new scene_basenode(name,"多边形");
		tmpPolygon.originalSceneRect = this.originalSceneRect;
		tmpPolygon.rotateangle = angle;
		tmpPolygon.originalpointArray = points;
		tmpPolygon.isboundingboxFill = true;

		let tmpRates = [];
		for(let i=0;i<points.length;i++){
			tmpRates[i] = new point(points[i].x / this.originalSceneRect.w,
				points[i].y / this.originalSceneRect.h);
		}
		tmpPolygon.pointRateArray = tmpRates;

		if(tmpPolygon.rotateangle != 0.0){
			tmpPolygon.rotateNode(tmpPolygon.rotateangle);
		}

		super.addChild(tmpPolygon);

		return tmpPolygon;		
	}

	/**
	 * 添加一个圆 
	 * @param name 圆的名称
	 * @param decrect 圆的显示范围
	 * @param angle 圆的显示角度，初始是0
	 */
	addCircular(name,decrect,angle=0.0) {
		let tmpCircular = new scene_circular(name,decrect);
		tmpCircular.originalSceneRect = this.originalSceneRect;
		tmpCircular.rotateangle = angle;

		let tmpPoints = [];
		tmpPoints[0] = new point(decrect.x,decrect.y);
		tmpPoints[1] = new point(decrect.x,decrect.y+decrect.h);
		tmpPoints[2] = new point(decrect.x+decrect.w,decrect.y+decrect.h);
		tmpPoints[3] = new point(decrect.x+decrect.w,decrect.y);
		tmpCircular.originalpointArray = tmpPoints;

		let tmpRates = [];
		for(let i=0;i<4;i++){
			tmpRates[i] = new point(tmpPoints[i].x / this.originalSceneRect.w,
				tmpPoints[i].y / this.originalSceneRect.h);
		}
		tmpCircular.pointRateArray = tmpRates;

		if(tmpCircular.rotateangle != 0.0){
			tmpCircular.rotateNode(tmpCircular.rotateangle);
		}

		super.addChild(tmpCircular);

		return tmpCircular;
	}	

	/**
	 * 添加一个矩形
	 * @param name 矩形的名称
	 * @param decrect 矩形的显示范围
	 * @param angle 矩形的显示角度，初始是0
	 * @param caption 矩形中要显示的文本
	 */
	addRectangle(name,decrect,angle=0.0,caption="") {
		let tmpRectangle = new scene_rectangle(name,"矩形");
		tmpRectangle.originalSceneRect = this.originalSceneRect;
		tmpRectangle.rotateangle = angle;
		tmpRectangle.isboundingboxFill = true;
		tmpRectangle.setDrawScene(this.drawscene);
		tmpRectangle.caption = caption;

		let tmpPoints = [];
		tmpPoints[0] = new point(decrect.x,decrect.y);
		tmpPoints[1] = new point(decrect.x,decrect.y+decrect.h);
		tmpPoints[2] = new point(decrect.x+decrect.w,decrect.y+decrect.h);
		tmpPoints[3] = new point(decrect.x+decrect.w,decrect.y);
		tmpRectangle.originalpointArray = tmpPoints;
		
		// 是否添加文本显示
		if(caption != "") {
			let tmpText = new scene_text(name+"_text",caption);
			//tmpText.isShowboundingBox = true;	
			tmpText.enableClip = false;
			tmpText.fillColor = '#ff0000';
			tmpText.textAlign = 'center';
			tmpText.originalSceneRect = this.originalSceneRect;
			tmpText.rotateangle = angle;
			tmpText.setDraggable(tmpRectangle.isDraggable());
			
			tmpRectangle.textctrl = tmpText;
			
			// 保存canvas老的字体
			let tmpoldfont = this.drawscene.font;
			// 设置新的字体
			this.drawscene.font = tmpText.font;
			
			let textHeight = parseInt(this.drawscene.font.match(/\d+(px)?/)[0], 10); 		
			let textWidth = decrect.w;
			
			// 还原为老的字体
			this.drawscene.font = tmpoldfont;
			
			// 字符控件始终显示在中间
			let tmpDecRectY = decrect.y+decrect.h/2-textHeight/2;

			let tmpPoints = [];
			tmpPoints[0] = new point(decrect.x,tmpDecRectY);
			tmpPoints[1] = new point(decrect.x,tmpDecRectY+textHeight);
			tmpPoints[2] = new point(decrect.x+textWidth,tmpDecRectY+textHeight);
			tmpPoints[3] = new point(decrect.x+textWidth,tmpDecRectY);
			tmpText.originalpointArray = tmpPoints;
			
			let tmpRates = [];
			for(let i=0;i<tmpPoints.length;i++){
				tmpRates[i] = new point(tmpPoints[i].x / this.originalSceneRect.w,
										tmpPoints[i].y / this.originalSceneRect.h);
			}
			tmpText.pointRateArray = tmpRates;

			if(tmpText.rotateangle != 0.0)
				tmpText.rotateNode(tmpText.rotateangle);
			
			tmpRectangle.addChild(tmpText);
		}		

		let tmpRates = [];
		for(let i=0;i<4;i++){
			tmpRates[i] = new point(tmpPoints[i].x / this.originalSceneRect.w,
				tmpPoints[i].y / this.originalSceneRect.h);	
		}
		tmpRectangle.pointRateArray = tmpRates;

		if(tmpRectangle.rotateangle != 0.0)
			tmpRectangle.rotateNode(tmpRectangle.rotateangle);

		super.addChild(tmpRectangle);

		return tmpRectangle;
	}

	/** 
	 * 添加一个线段控件
	 * @param name 线段的名称
	 * @param startpos 线段的开始坐标
	 * @param endpos 线段的结束坐标
	 * @param angle 线段的显示角度，初始是0 
	 */
	addLine(name,startpos,endpos,angle=0.0) {
		let tmpLine = new scene_line(name,startpos,endpos);
		tmpLine.originalSceneRect = this.originalSceneRect;
		tmpLine.rotateangle = angle;

		let tmpPoints = tmpLine.lineNode.boundingBox().getPolygonPoints();
		tmpLine.originalpointArray = tmpPoints;
		
		let tmpRates = [];
		for(let i=0;i<tmpPoints.length;i++){
			tmpRates[i] = new point(tmpPoints[i].x / this.originalSceneRect.w,
									tmpPoints[i].y / this.originalSceneRect.h);
		}
		tmpLine.pointRateArray = tmpRates;

		if(tmpLine.rotateangle != 0.0){
			tmpLine.rotateNode(tmpLine.rotateangle);
		}

		super.addChild(tmpLine);

		return tmpLine;		
	}

	/**
	 * 添加一个文本控件
	 * @param name 文本控件的名称
	 * @param position 文本控件的显示位置
	 * @param title 文本控件的显示内容
	 * @param angle 文本控件的显示角度，初始是0 
	 */
	addText(name,position,title,font='16px Calibri',angle=0.0) {
		let tmpText = new scene_text(name,title,font);
		tmpText.originalSceneRect = this.originalSceneRect;
		tmpText.rotateangle = angle;

		// 保存canvas老的字体
		let tmpoldfont = this.drawscene.font;
		// 设置新的字体
		this.drawscene.font = font;
		
		let textHeight = parseInt(this.drawscene.font.match(/\d+(px)?/)[0], 10); 		
		let textWidth = this.drawscene.measureText(title).width-textHeight*2;
		
		// 还原为老的字体
		this.drawscene.font = tmpoldfont;

		let tmpPoints = [];
		tmpPoints[0] = new point(position.x,position.y);
		tmpPoints[1] = new point(position.x,position.y+textHeight);
		tmpPoints[2] = new point(position.x+textWidth,position.y+textHeight);
		tmpPoints[3] = new point(position.x+textWidth,position.y);
		tmpText.originalpointArray = tmpPoints;
		
		let tmpRates = [];
		for(let i=0;i<tmpPoints.length;i++){
			tmpRates[i] = new point(tmpPoints[i].x / this.originalSceneRect.w,
									tmpPoints[i].y / this.originalSceneRect.h);
		}
		tmpText.pointRateArray = tmpRates;

		if(tmpText.rotateangle != 0.0){
			tmpText.rotateNode(tmpText.rotateangle);
		}

		super.addChild(tmpText);

		return tmpText;		
	}

	/**
	 * 改变场景的位置
	 * @param relativex 要改变的场景的相对位置X
	 * @param relativey 要改变的场景的相对位置Y
	 */
	resizeScenePosition(relativex,relativey) {	
		this.originalSceneRect = new rect(relativex,relativey,
									      this.originalSceneRect.w,this.originalSceneRect.h);
										  
		for(let i=0;i<this.childNodes.length;i++){
			this.childNodes[i].resizeScene(this.originalSceneRect);
		}	

		if(this.systemResizeSceneFunction) this.systemResizeSceneFunction(this.originalSceneRect);		
	}

	/// 改变渲染场景大小
	adaptiveScene(){
		if(this.adaptivescreen == false ||
		   (this.originalSceneRect.w == window.innerWidth-20 && this.originalSceneRect.h == window.innerHeight-20)) return;
		
		// 获取视口宽度和高度  
		const screenwidth = window.innerWidth-20;  
		const screenheight = window.innerHeight-20;  
			
		this.tmpcanvas.width = screenwidth;  
		this.tmpcanvas.height = screenheight; 
		this.drawscene = this.tmpcanvas.getContext("2d");
				
		this.canvasrect = this.tmpcanvas.getBoundingClientRect();
		this.originalSceneRect = new rect(0,0,this.canvasrect.width,this.canvasrect.height);
		this.tmpboundingbox = this.originalSceneRect;

		for(let i=0;i<this.childNodes.length;i++){
			this.childNodes[i].updateNode(this.originalSceneRect);
			this.childNodes[i].resizeScene(this.originalSceneRect);
		}	

		if(this.systemResizeSceneFunction) this.systemResizeSceneFunction(this.originalSceneRect);		
	}

	/// 滚动场景
	wheelScene(wheel) {	
		this.originalSceneRect = new rect(this.originalSceneRect.x-wheel,this.originalSceneRect.y-wheel,
			                          this.originalSceneRect.w+wheel*2,this.originalSceneRect.h+wheel*2);

		for(let i=0;i<this.childNodes.length;i++){
			this.childNodes[i].resizeScene(this.originalSceneRect);
		}	

		if(this.systemResizeSceneFunction) this.systemResizeSceneFunction(this.originalSceneRect);
	}	
	
	/// 缩放结点
	wheelNode(node,wheel) {
		if(node == null || !node.isScaleable()) return;
		
		node.scaleLength += wheel;		
		node.resizeScene(this.originalSceneRect);
	}

	/// 画包围盒
	drawboundingBox(ctx,drawrect) {
		if(this.isShowboundingBox == false || ctx == null)
			return;
		
		//ctx.save(); 
		
		ctx.beginPath();	
		ctx.strokeStyle='#00ff00';
		ctx.fillStyle='#000000';  
		//ctx.fillRect(0,0,this.canvasrect.width,this.canvasrect.height);  		
		ctx.rect(this.originalSceneRect.x,this.originalSceneRect.y,
			     this.originalSceneRect.w,this.originalSceneRect.h);	
		ctx.clip();			
		ctx.strokeRect(this.originalSceneRect.x,this.originalSceneRect.y,
					   this.originalSceneRect.w,this.originalSceneRect.h);
		ctx.stroke();
		ctx.closePath();
		//ctx.restore();
	}	

	/// 更新场景
	updateScene() {
		/// 更新所有的结点
		for(let i=0;i<this.childNodes.length;i++){
			this.childNodes[i].updateNode(this.originalSceneRect);
		}		
	}

	/// 绘制场景
	drawScene() {	
		this.drawscene.save();
		
		this.drawscene.fillStyle='#000000';  
		this.drawscene.fillRect(0,0,this.canvasrect.width,this.canvasrect.height);  		
		
		// 显示包围盒
		this.drawboundingBox(this.drawscene,this.canvasrect);
		
		/// 绘制基础图像
		this.drawBaseImage(this.drawscene);			

		// 绘制所有的结点
		for(let i=0;i<this.childNodes.length;i++){
			this.childNodes[i].drawNode(this.drawscene);
		}	
		
		this.drawscene.restore();	
		
		if(this.currentMouseOverNode && 
		   this.currentMouseOverNode.mouseState == "move" && 
		   this.currentMouseOverNode.showTip && 
		   this.currentMouseOverNode.caption != ""){
	
			let tmpboundingbox = this.currentMouseOverNode.boundingBoxpolygon.getboundingBoxrect();
			let tmpshowX = tmpboundingbox.getCenter().x;
			let tmpshowY = tmpboundingbox.getCenter().y;
		
			this.drawscene.save();		
			this.drawscene.beginPath();
			this.drawscene.strokeStyle="#000000";
			this.drawscene.fillStyle="#ffffff";
			this.drawscene.lineWidth=0.5;
			this.drawscene.font = '12pt Calibri';
				
			let textHeight = parseInt(this.drawscene.font.match(/\d+(px)?/)[0], 10); 		
			let textWidth = this.drawscene.measureText(this.currentMouseOverNode.caption).width;
			
			this.drawscene.fillRect(tmpshowX,tmpshowY,textWidth,textHeight);
			this.drawscene.strokeRect(tmpshowX,tmpshowY,textWidth,textHeight);			
			
			this.drawscene.fillStyle="#ff0000";
			this.drawscene.textAlign = "left";
			this.drawscene.textBaseline = "top";					
			this.drawscene.fillText(this.currentMouseOverNode.caption,tmpshowX,tmpshowY+1);
			this.drawscene.closePath();
			this.drawscene.restore();	
		}		
	}	
}